package org.zbclan.bf2.rcon;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class SoundPlayback implements SoundRunnable {

	// private static final int bufferSize = 16384;

	private final Callback callback;

	private Thread thread;
	private SourceDataLine line;

	public SoundPlayback(Callback callback) {

		if (callback == null) {
			throw new IllegalArgumentException("callback required");
		}

		this.callback = callback;

		return;
	}

	@Override
	public void run() {

		line.start();

		int bufferLengthInBytes = (line.getBufferSize() / 8) * frameSize;
		byte[] data = new byte[bufferLengthInBytes];
		int numBytesRead;

		while (thread != null) {
			numBytesRead = callback.fetch(data);
			if (numBytesRead == -1) {
				break;
			}

			int numBytesRemaining = numBytesRead;
			while (numBytesRemaining > 0) {
				numBytesRemaining -= line.write(data, 0, numBytesRemaining);
			}
		}

		line.stop();

		line.close();

		return;
	}

	public synchronized void start(LineListener listener)
			throws LineUnavailableException {
		if (thread == null) {
			line = (SourceDataLine) AudioSystem.getLine(new DataLine.Info(
					SourceDataLine.class, format));
			line.addLineListener(listener);
			// line.open(format, bufferSize);
			line.open(format);

			thread = new Thread(this, "SoundPlayback");
			thread.setDaemon(true);
			thread.start();
		}
	}

	public synchronized void stop() {
		thread = null;
		line.flush();
	}

	public synchronized void pause() {
		if (thread != null) {
			line.stop();
		}
	}

	public void resume() {
		if (thread != null) {
			line.start();
		}
	}

	public interface Callback {

		/**
		 * @param buffer
		 * @return number of byte available in buffer
		 */
		int fetch(byte[] buffer);
	}

	public static void main(String[] args)
			throws UnsupportedAudioFileException, IOException,
			LineUnavailableException {

		// final AudioInputStream audioInputStream = AudioSystem
		// .getAudioInputStream(new File("c.wav"));
		File file = new File("c.wav");
		// final AudioInputStream audioInputStream = new AudioInputStream(
		// new FileInputStream(file), SoundRunnable.format, file.length()
		// / SoundRunnable.frameSize);
		final AudioInputStream audioInputStream = new AudioInputStream(
				new FileInputStream(file), SoundRunnable.format,
				AudioSystem.NOT_SPECIFIED);

		SoundPlayback soundPlayback = new SoundPlayback(
				new SoundPlayback.Callback() {

					@Override
					public int fetch(byte[] buffer) {
						int read;
						try {
							read = audioInputStream.read(buffer);
						} catch (IOException ex) {
							ex.printStackTrace();
							read = -1;
						}
						return read;
					}
				});
		soundPlayback.start(new LineListener() {

			@Override
			public void update(LineEvent event) {
				System.out.println(event.getType().toString());
			}
		});

		return;
	}
}
